#!/usr/bin/python2.5
# -*- coding: utf8 -*-
import bot
import dict4ini
import sys
import time
#import gui

from ini import *
from utils import *
#from Tkinter import *

def log(*args):
	"Replacement for print, which doesn't deal with unicode well"
	msg=u" ".join(map(unicode,args))
	# Replace unencodable charactors with ?
	#print >>bot.logf, time.strftime("%Y-%m-%d %H:%M:%S"), msg.encode(sys.getdefaultencoding(),"replace")
	print >>bot.logf, time.strftime("%Y-%m-%d %H:%M:%S"), msg.encode('utf-8')
	bot.logf.flush()
	#print time.strftime("%H:%M:%S"), msg.encode(sys.getdefaultencoding(),"replace")
	print time.strftime("%H:%M:%S"), msg.encode('utf-8')

#Command "RAISE" exception classes
class COMMAND_HELP(Exception):pass

class ConferenceBot(bot.Bot):
	def __init__(self):
		global config
	
		#Define .ini lists
		config = cbot2
		self.config = cbot2
		
		#Start all the behind the scenes functions.
		bot.Bot.__init__(self,
			core.required.username,
			core.required.password,
			core.required.domain)

		#Plugin hashing dictionary
		self.pluginhash = {}
		
		#Define command dictionarys.
		self.commands = {}
		self.modcommands = {}
		self.admincommands = {}
		self.mutecommands = {}
		self.hooks = {}
		
		self.games = {}
		self.games["roomai"] = []
		self.games["math"] = []
		
		#Core settings are module independant and should be loaded first.
		readcore(self)
		core.required.module = "cbot2" #Set currently used module.
		savecore()
		
		#Load all bot settings.
		readall()
		saveall()
		
		confirmdir("errors")
		pluglog = file(os.path.join("errors", "PluginError.log"), "a+")
		#Load all external plugins and warn the user about missing plugins.
		for i in config.system.plugins.split(" "):
			try:	
				a = open(os.path.join("plugins","plugin_%s.py") % i,"r").read()
				plugin = {}
				exec a in plugin
				debug('core',"Loading plugin %s" % i)
				plugin["init"](self)
				self.pluginhash[i] = hash(a)
			except IOError:
				print 'The plugin "plugin_%s.py" could not be found.' % args
				continue
			except:
				traceback.print_exc()
				print >>pluglog, "\n Plugin error log for: ", i
				traceback.print_exc(None, pluglog)
				print 'There was an error importing the plugin. A report has been logged.'
				continue
		pluglog.close()

	def log(self,*args):
		log(*args)

	def addCommand(self,name,command):
		self.commands[name] = command

	def addModCommand(self,name,command):
		self.modcommands[name] = command
		
	def addAdminCommand(self,name,command):
		self.admincommands[name] = command
		
	def addMuteCommand(self, name, command):
		self.mutecommands[name] = command
		
	def removeCommand(self, names, command_name = None):
		for group in [self.commands, self.modcommands, self.admincommands, self.mutecommands]:
			for name in names:
				if command_name:
					if name in group and group[name].__name__ in command_name:
						del group[name]
				else:
					if name in group:
						del group[name]

	def addHook(self, name, command):
		if name in self.hooks:
			self.hooks[name].append(command)
		else:
			self.hooks[name] = [command]
			
	def removeHook(self, hook_name):
		try:
			for group, hooks in self.hooks.items():
				for hook in hooks:
					if hook.__name__ in hook_name:
						self.hooks[group].remove(hook)
						break
		except ValueError:
			pass
		except:
			traceback.print_exc()
		
		for group in self.hooks:
			if group == []:
				del self.hooks[group]

	def hook(self,name,*args):
		# Multiple plugins can register hooks, the first one to
		# return True causes all further processing of that hook
		# to be aborted.
		if name in self.hooks:
			for hook in self.hooks[name]:
				if hook(self,args):
					return False
			return True

	def command(self,user,msg):
		msg = unicode(msg).encode('utf-8')
		if " " in msg:
			cmd,args = msg.split(" ",1)
		else:
			cmd,args = msg.strip().lower(),""
		try:
			if ismuted(user):
				if cmd in self.mutecommands:
					func = self.mutecommands[cmd]
					func(self,user,args)
			elif cmd in self.commands:
				func = self.commands[cmd]
				func(self,user,args)
			elif cmd in self.modcommands:
				if ismod(user) or isadmin(user):
					func = self.modcommands[cmd]
					func(self,user,args)
				else:
					self.error(user, "You must be a moderator to use that command.")
			elif cmd in self.admincommands:
				if isadmin(user):
					func = self.admincommands[cmd]
					func(self,user,args)
				else:
					self.error(user,"You must be an admin to use that command.")
			else:
				self.error(user,"Unknown command, try )help")
		except COMMAND_HELP:
			self.sys(user, func.__doc__)
					
	def sendtoall(self, msg, butnot = [], name = '', log = False):
		for user in self.getRoster():
			# Skip any users in butnot
			if unicode(user) in butnot:
				continue
			for resource,(status,display) in self.getJidStatus(user).items(): 
				# Ignore people who aren't online
				if self.hook("recieve", user) and status not in [u"offline",u"dnd"] and not isaway(getjid(resource)):
					if name:
						format = formatmessage(user, "main", u'<%(name)s> %(msg)s')
					else:
						format = u'%(msg)s'
					self.msg(resource, format % {"time":time.strftime('%I:%M %p'),"name":name,"msg":msg})
				elif name and name == "Announcement" and status != "dnd":
					self.msg(resource, formatmessage(user, "main", u'<%(name)s> %(msg)s',
										time = time.strftime('%I:%M %p'), 
										name = name, 
										msg = msg
										))
					
		if log:
			if name:
				self.log(u'<%(name)s> %(msg)s' % {"name":name,"msg":msg})
			else:
				self.log(msg)
				
	def sendtoroom(self, msg, room, butnot = [], name = '', log = False):
		for user in rooms[room]:
			if unicode(user) in butnot:
				continue
			for resource,(status,display) in self.getJidStatus(user).items(): 
				# Ignore people who aren't online
				if status in [u"online",u"chat"] and not isaway(getjid(resource)):
					if name:
						format = formatmessage(user, "main", u'<%(name)s> %(msg)s')
					else:
						format = u'%(msg)s'
					self.msg(resource, format % {"name":name,"msg":msg})
		if log:
			if name:
				self.log(u'[%(room)s] <%(name)s> %(msg)s' % {"room":room, "name":name, "msg":msg})
			else:
				self.log(u'[%(room)s] %(msg)s' % {"room":room, "msg":msg})
					
	def sendto(self, msg, butnot = [], user = '', name = '', log = False):
		"Send to all unless the user is in a room, then send to room."
		if user:
			user_room = getroom(user)
			if user_room:
				sendtoroom(msg, user_room, butnot, name, log)
				return
				
		sendtoall(msg, butnot, name, log)			
					
	def sys(self, user, msg):
		self.msg(user, config.system.sysprefix + " " + msg)
	
	def systoall(self, msg, butnot=[], log = True):
		self.sendtoall(config.system.sysprefix + " " + msg, butnot, log = log)
	
	def error(self, user, msg):
		"Send an error message to a user"
		self.msg(user,"ERROR: " + msg)
		
			
	def ev_msg(self, user, msg):
		# Is this a command?
		if msg[:1] in config.system.commandprefix:
			self.command(user,msg[1:])
		elif getroom(user):
			msg = autocomplete(clean_string(msg))
			
			room = getroom(user)
			self.log("["+room+"] <"+getdisplayname(user)+">",msg)
			
			self.sendtoroom(msg, room, butnot=[unicode(user.getStripped())], name=unicode(getdisplayname(user)))
			#Update when the user last sent a message if the message got through.
			set_userflag(user,"last msg", time.time())
			
		elif getjid(user) != getjid(core.required.username):
			msg = autocomplete(clean_string(msg))
			
			self.log("<"+getdisplayname(user)+">",msg)

			if self.hook("message", user, msg):
				self.sendtoall(msg,butnot=[unicode(user.getStripped())], name=unicode(getdisplayname(user)))
				#Update when the user last sent a message if the message got through.
				set_userflag(user,"last msg", time.time())

	def ev_unsubscribe(self,user,msg):
		# User removed us from their list
		# So remove them from ours.
		log(user,"unsubscribing:",msg)
		del userlist[user]
		self.removeUser(user)
		self.rejectUser(user)
		self.refreshRoster()

	def ev_unsubscribed(self,user,msg):
		# User has forced us to remove them from our list
		log(user,"unsubscribing:",msg)
		del userlist[user]
		self.removeUser(user)
		self.rejectUser(user) # Remove us from their list
		self.refreshRoster()

	def ev_subscribe(self,user,msg):
		if isbanned(user):
			self.rejectUser(user)
		else:
			# User added us to their list, so add them to ours
			log(user,"subscribing:",msg)
			self.addUser(user)
			self.acceptUser(user)
			self.refreshRoster()

	def ev_online(self, user, msg):
		#Update the last time a user was online.			
		set_userflag(user,"last login", time.time())
		self.statuschange(user,'online')

	def ev_unavailable(self,user,msg):
		self.statuschange(user,'offline')

	def ev_away(self,user,msg):
		self.statuschange(user,'away')

	def ev_chat(self,user,msg):
		self.statuschange(user,'chat')

	def ev_dnd(self,user,msg):
		self.statuschange(user,'dnd')

	def ev_xa(self,user,msg):
		self.statuschange(user,'xa')

	def statuschange(self,user,status):
		#self.systoall('%(name)s is %(status)s.' % {"name":(getdisplayname(user)), "status":status}, [user])
		pass


	
	
me = ConferenceBot()

if me.jid.getDomain() == "gmail.com":
	me.connect(("talk.google.com",5223), use_srv = False, resource = 'conference')
else:
	me.connect(resource = 'conference')

me.setOnline(module.system.status)
#Add any new users.
for i in me.getRoster():
	i = getjid(i)
	if i not in userlist.keys():
		adduser(getcleanname(i))
		
debug('core', "The bot is now online!\nRunning version: %s\nAt %s" % (get_svn_version(), time.strftime("%Y-%m-%d %H:%M:%S")))
me.run()
